<?php
/*-- Project Introduce --*/
namespace JCAT\Core\OOP ;

use JCAT\Core\Event;
include_once( __DIR__.'/class.PHPPackage.php' ) ;
include_once( __DIR__.'/../Event/class.KernelEventManager.php' ) ;

/**
 * 用于管理 class(interface) 的加载
 *
 * @author		alee
 * @access		public
 */
class PHPClassLoader
{
	/**
	 * Description
	 *
	 * @access	public
	 * @static 
	 * @return	JCAT_ClassLoader
	 */
	static public function GetGlobalInstance(Event\KernelEventManager $aEventManager=null)
	{
		if( !self::$aGlobalInstance )
		{
			if(!$aEventManager)
			{
				$aEventManager = Event\KernelEventManager::GetGlobalInstance() ;
			}
			self::$aGlobalInstance = new PHPClassLoader($aEventManager) ;
		}
		
		return self::$aGlobalInstance ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param 	$aInstance	JCAT_ClassLoader
	 * @static 
	 * @return	void
	 */
	static public function SetGlobalInstance(self $aInstance)
	{
		self::$aGlobalInstance = $aInstance ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	void
	 */
	public function PHPClassLoader(Event\KernelEventManager $aEventManager)
	{
		// 注册 autoload 事件
		$aEventManager->RegisterKernelHandle(Event\PHP_AUTOLOAD,array($this,'LoadClass')) ;
	}
	

	/**
	 * 自动加载 类/接口 文件 开关
	 * 
	 * @access	public
	 * @param	$bAutoload=true		bool		是否自动加载
	 * @return	old_value
	 */
	public function EnableAutoload($bIsAutoload)
	{
		$old_value = $this->bAutoload ;
		$this->bAutoload = $bIsAutoload? true: false ;
		return $old_value ;
	}

	/**
	 * 自动加载 类/接口 文件 状态
	 * 
	 * @access	public
	 * @return	bool
	 */
	public function IsEnableAutoload()
	{
		return $this->bAutoload ;
	}
	
	/**
	 * 在执行 php 原生函数 class_exists() 或  interface_exists()  的时候，如果存在符合 文件命名规则的类(接口)文件，JCAT框架 会自动 加载。
	 * 此方法 JCAT_Package::ClassExists() 效果等同，但是提供 是否自动加载的 选择。
	 * 
	 * @access	public
	 * @param	$sClassOrInterfaceName		string			类 或 接口名称
	 * @param	$bInterface=false			bool			指示 参数 $sClassOrInterfaceName 是否是一个接口
	 * @param	$bAutoloadIfFind=false		string			如果依据 文件命名规则 找到 类文件，是否自动加载
	 * @return	bool
	 */
	public function ClassExists($sClassOrInterfaceName,$bInterface=false,$bAutoloadIfFind=false)
	{
		$bAutoloadOldValue = $this->EnableAutoload($bAutoloadIfFind) ;
		
		$sFuncName = $bInterface? 'interface_exists': 'class_exists' ;
		$bRet = $sFuncName($sClassOrInterfaceName) ;
		
		$this->EnableAutoload($bAutoloadOldValue) ;
		return $bRet ;
	}
	
	/**
	 * __autoload 的实际处理函数
	 * 
	 * @access	public
	 * @param	$sClassOrInterface		string	正在载入的 类名 或 接口名
	 * @return	void
	 */
	public function LoadClass( $sClassOrInterface ) 
	{
		if( !$this->IsEnableAutoload() )
		{
			return ;
		}
		
		$sClassPath = $this->QueryClass($sClassOrInterface) ;		
		if($sClassPath)
		{
			require $sClassPath ;
		}
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$sClassOrInterface
	 * @return	string
	 */
	public function QueryClass($sClassOrInterface)
	{
		foreach ($this->arrLoadedPackages as $aPackage)
		{
			$sClassPath = $aPackage->QueryClass($sClassOrInterface) ;
			if($sClassPath)
			{
				return $sClassPath ;
			}
		}
		
		return null ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	JCAT_IIterator
	 */
	public function CreateClassNameIter()
	{
		$arrPackageIters = array() ;
		foreach ($this->arrLoadedPackages as $aPackage)
		{
			$arrPackageIters[] = $aPackage->CreateClassNameIter() ;
		}
		return new JCAT_MultiIterator($arrPackageIters) ; 
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$Parameter
	 * @return	void
	 */
	public function __sleep()
	{
		return array(
			MakePrivateNameForSerialize('arrLoadedPackages',__CLASS__)
		) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$aPackage		JCAT_ClassPackage
	 * @return	void
	 */
	public function AddPackage(PHPPackage $aPackage)
	{
		if( !in_array($aPackage,$this->arrLoadedPackages,true))
		{
			array_unshift($this->arrLoadedPackages,$aPackage) ;
		}
	}
	
	/**
	 * 导入整个包
	 * 
	 * @access	public
	 * @param	$sPackage							string		被导入的包的路径
	 * @param	$sNS								string		包的命名空间
	 * @param	$bForceRefreshCache=fasle			bool		强制重建 Classes Path 文件
	 * @return	void
	 */
	public function Import( $sPackage, $sNS, $bForceRefreshCache=false ) 
	{
		$aPackage = new PHPPackage($sPackage,$sNS) ;
		$aPackage->LoadClassList($bForceRefreshCache) ;
		
		$this->AddPackage($aPackage) ;
		return $aPackage ;
	}
	
	/**
	 * Description
	 * 
	 * @access	private
	 * @var		array
	 */
	private $arrLoadedPackages = array() ;
	
	/**
	 * Description
	 * 
	 * @access	private
	 * @var		bool
	 */
	private $bAutoload = true ;
	
	
	/**
	 * Description
	 * 
	 * @access	private
	 * @static
	 * @var		JCAT_EventManager
	 */
	static private $aGlobalInstance ;
}

?>